import ogre.renderer.OGRE as ogre
import ogre.io.OIS as OIS
from OpenSteer import pyopensteer2D as OpenSteer
from util.interfaces import IDestroyable,ITimerUpdatable,ISelectable
from decodeSVG import decodeSVG

import util.util
from AStar.AStar import AStar, SQ_Location, SQ_MapHandler

import math


import logging
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                    filename='xenocide.log',
                    filemode='w',
                    level=logging.DEBUG)
logging.info('Strat logging')


class World:
    
    SELECTABLE_MASK=0x10
    ALIEN_MASK=0x02
    HUMAN_MASK=0x04
    TERRAIN_MASK=0x08
    
    QUERY_GROUND =0x1   
    QUERY_OTHER_OBJECT=0x2
    QUERY_CURRENT_ACTOR=0x3
    QUERY_OTHER=0x4
    QUERY_EMPTY=0x5
    QUERY_TERRAIN=0x6
    
    #Value used to blank an obstacle map
    #This value represents the minimum energy level for an A* algorithm
    MAP_BLANK=0x00
    #This value represents the maximum energy level for an A* algorithm
    #The A* algorithm will never pass on an area with this value
    MAP_FORBIDDEN=0xFF
     

    
    def __init__(self,win, iWorldDim):
      
        
        self.levelName="level1"
        #parent window
        self.MainWindow=win
        #dictionary of actors
        self.actors={}
        #dictionary of Icebergs
        self.icebergs={}
        #dictionary of barrier poles
        self.barrierPoles = {}
        #dictionary of links
        self.links = {}

        #list of objects to be updated during timer events
        self.updatables = []
        #list of objects to be deleted at end of timer events
        self.queueOfDeath = []
        
        #dimensions of the world, to be compared with the dim of the map
        self.worldDim = iWorldDim
        
        self.mapCenter=ogre.Vector3(0.5*iWorldDim[0],0.0,0.5*iWorldDim[1])
        
        self.currentSelection=None
        
        self.map=[]
        self.friendlyMap=[]
        self.mapDim=(0,0)
        
        self.mapFactor=(0,0)
        
        #LOAD the floating icebergs from a svg file
        pData=ogre.ResourceGroupManager.getSingleton().openResource( self.levelName+".svg", ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME )
        xmlstr=pData.getAsString()
        svg=decodeSVG.SVGParser(xmlstr)
        pData.close()
        self.createIcebergs(svg.getPaths())
        
        self.loadMap( self.levelName+".png")

        self.friendlyMap=self.makeMap(self.mapDim)
        
        # counter for Barrier POles
        self.bpCounter=0

        #counter for Links
        self.liCounter=0
        
        self.loopCounter=200
        self.infoflag=False
        
        self.BBS= GlowingBillboard(self,win.SceneMgr.getRootSceneNode().createChildSceneNode(),\
                            "selection set","Alpha/RedLight")
        
        self.updatables.append(self.BBS)
    
    def __del__(self):
        pass
    
    def test(self):
        ma=self.actors.values()[0]
        ma.addWayPoint(ogre.Vector3(-200.,0,100.),False,False)
    
    
    def createIcebergs(self,svgPaths):
        self.icebergs.clear()
        
        for i in range(len(svgPaths)):
            name="Iceberg#%d"%(i)
            
            self.icebergs[name]=Iceberg(self,name,svgPaths[i])
            
            
            
            
    def spawnMobileActor(self, iName,iPos, iOrient, iMeshFile,iMaterial):

        if iName in self.actors:
            print("***WARNING*** :spawn failed : name [%s] already exists.",iName)
            return None

        ma=None
        print("Intenting creating MA",iName,iPos,iMeshFile)
        ma=MobileActor(self,iName,iPos,iOrient,iMeshFile,iMaterial)
        
        if ma is not None:
            self.actors[iName]=ma
            print "Actor "+iName+" added "+str(len(self.actors))
        
        #logging.info('Size of actors: '+str(len(self.actors)))

        n=0
        for x in self.actors.values():
            #logging.info(" actor %i : %s at pos %s"%(n,x.getName(),self.strV3(x.getPosition())))
            n+=1
            
        return ma

    def destroyActor(self,ma):
        if ma.name in self.actors:
                self.queueOfDeath.append(ma)
               
    def destroyBarrierPole(self,bp):
        print "Destroying BP "+bp.name
        if bp.name in self.barrierPoles:
                print "Found !"
                self.queueOfDeath.append(bp)
        else : print "NOT Found !"
        
    def getBarrierLink(self, iBP1, iBP2):
    
        for bl in self.links.values():
            if bl.isLinking(iBP1) and bl.isLinking(iBP2):
                return bl
        
        return None
    
    def getBarrierLinks(self, iBP1):
        blq = []
        for bl in self.links.values():
            if bl.isLinking(iBP1) :
                blq.append(bl)
            
        return blq
    
    def createBarrierLink(self, iBP1, iBP2):
        
        bl = self.getBarrierLink(iBP1, iBP2)
        iName = "BarrierLink#" + str(self.liCounter)
        self.liCounter=self.liCounter+1
        
        if not bl:
        
            bl = BarrierLink(iName, iBP1, iBP2, self)
            self.links[iName]=bl
            self.updateFriendlyMap()
            print("BL created OK")
        
        else:
            print(" Failed creating BL "+iName)
        
        return bl
    
    def destroyBarrierLink(self, iName1,  iName2):
    
        if iName1 in self.barrierPoles and  iName2 in self.barrierPoles:
            print("Intenting to destroy BL linking " + iName1 + " & " + iName2)
            self.destroyBarrierLink(self.barrierPoles[iName1], self.barrierPoles[iName2])
            
    def destroyBarrierLinks(self,iBP1):
        
        blq = self.getBarrierLinks(iBP1)
        
        for i in range(len(blq)):
            bl = blq.pop()
            del self.links[bl.name]
            del bl
            
        self.updateFriendlyMap()
    
    
    def updateFriendlyMap(self):
        """ Updates the friendly map with the current barrier status """    

        self.friendlyMap=self.makeMap(self.getMapDim(self.friendlyMap))
        
        
        for bl in self.links.values():
            BPs = bl.getPeers()
            pts= (self.getMapCoord(BPs[0].getPosition()),self.getMapCoord(BPs[1].getPosition()))
            
            self.drawLine(pts,self.friendlyMap,self.MAP_FORBIDDEN)
        
        #self.printmap(self.friendlyMap)
        
    def spawnBarrierPole(self, iPos):
    
        iName="BarrierPole#"+str(self.bpCounter)
        self.bpCounter=self.bpCounter+1
        
        
        bp = BarrierPole(self,iPos, iName,  self.friendlyMap)
        self.updatables.append(bp)
        self.barrierPoles[bp.getName()]=bp
        return bp
    
    def getSelectableByName(self, iName):
        if iName in self.actors:
            return self.actors[iName]
        
        if iName in self.barrierPoles:
            return self.barrierPoles[iName]
        
        return None
        
    def getActorByName(self, iName):
        if iName in self.actors:
            return self.actors[iName]
        
        return None

    def doFrameStarted(self,evt):
        dt=evt.timeSinceLastFrame
        self.loopCounter+=1
        self.infoflag=False
        if self.loopCounter>=200:
            self.infoflag=True
            self.loopCounter=0
            
        for ma in self.actors.values():
            
            if self.infoflag:
                logging.info("UPDATE %s at pos %s *** %s"%(ma.getName(),self.strV3(ma.getPosition()),str(ma.lv.getPosition())))
            ma.timerUpdate(dt )    
            #depht = self.getMapValue(self.getMapCoord(ma.getPosition()),self.map)
            #if depht > ma.Size*2 :
            #self.destroyActor(ma)
        
    
        for tu in self.updatables :
            tu.timerUpdate(dt)

        
        
        for i in range(len(self.queueOfDeath)):
            mo=self.queueOfDeath.pop()
            if mo.type:
            
                
                if mo.type=="MobileActor" and  mo.name in self.actors:
                
                    del self.actors[mo.name]
                    if self.currentSelection == mo:
                        self.currentSelection = None
            
                if mo.type=="BarrierPole" and  mo.name in self.barrierPoles:
                    self.destroyBarrierLinks(mo)
                    
                    print "destroying "+mo.name
                    del self.barrierPoles[mo.name]
                    
            
                del mo
        return True
    
    def strV3(self,v):
        return "V3"+str(tuple([v[i] for i in range(3)]))
        
    def loadMap(self,iName):
        
            resolution =1
            img=ogre.Image()

            img.load(iName,ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME)

            self.mapDim = ((img.Width / resolution),(img.Height / resolution))
            self.mapFactor=(self.mapDim[0]*1.0 / self.worldDim[0], self.mapDim[1]*1.0  / self.worldDim[0])
            
            self.map=self.makeMap(self.mapDim)
            (w,h)=self.mapDim
            #self.printmap(self.map)
            for j in range(h):
                for i in range(w):
                    c = img.getColourAt(i * resolution, j * resolution, 0)
                    self.setMapValue(self.map,(i,j),(c.r + c.g + c.b) * 30+5)
                
    def getMapDim(self,map):
        return map[-1]
    
    def printmap(self,b):
        (w,h)=self.getMapDim(b)
        
        for i in range(h):
            print [b[j] for j in range(i*w,i*w+w)]
            
    def makeMap(self,dim):
        (w,h)=dim
        map=[self.MAP_BLANK]*(w*h)
        map.append(dim)
        return map
    
        
    def drawLine(self,pts,iMap,iBlackValue):
        """Draws a line in a binary 2 dimentional array.
        The line is drawn so that no diagonal is used (leave no blank space if a barrier is drawn)."""
        ((xi,yi),(xf,yf)) = pts
        
        
        dx = xf - xi
        dy = yf - yi

        x=xi
        y=yi
        

        if dx > 0 : xinc=1;
        else : xinc=-1;
        
        if dy > 0 : yinc=1;
        else : yinc=-1;
       
        dx=math.fabs(dx)
        dy=math.fabs(dy)

        self.setMapValue(iMap,(x,y),iBlackValue)
        if dx > dy:
            cumul = dx / 2
            for i in range(1,dx+1):
                x = x+xinc
                cumul = cumul+dy

                if cumul >= dx:
                
                    cumul = cumul- dx
                    self.setMapValue(iMap,(x,y),iBlackValue) # to avoid empty diagonals
                    y = y+ yinc
                
                self.setMapValue(iMap,(x,y),iBlackValue)
        
        else:
            cumul = dy / 2
            for i in range(1,dy+1):
            
                y =y+ yinc
                cumul = cumul + dx

                if cumul >= dy :
                
                    cumul = cumul - dy
                    self.setMapValue(iMap,(x,y),iBlackValue)
                    x = x + xinc
                
                self.setMapValue(iMap,(x,y),iBlackValue)


    def getMapValue(self, iP,iMap):
        """ Takes a tuple (x,y) as argument"""
        
        (x,y)=iP
        (w,h)=self.getMapDim(iMap)
        x = min(x, w-1)
        y = min(y, h-1)
       
        if x < 0 : x= 0
        if y < 0 : y= 0
         
        return iMap[x+y*w]
    
    def setMapValue(self,iMap,iP,iVal):
        (x,y)=iP
        (w,h)=self.getMapDim(iMap)
        x = min(x, w-1)
        y = min(y, h-1)
        
        if x < 0 : x= 0
        if y < 0 : y= 0
        
        iMap[x+y*w]=iVal
        
        
  
    def getMapCoord(self, ipos):
        
        """ Returns a position on the map corresponding to a Vector3 pos in the world
        Takes a ogre.Vector3 as argument"""
         
        if not self.mapDim[0]* self.mapDim[1]==0:
        
            return  ((int)((self.mapCenter[0] - ipos.x) * self.mapFactor[0]),\
                    (int)(((-ipos.z +self.mapCenter.z))* self.mapFactor[1]))
        
        return None
    
    def getWorldCoord(self, iP):
        """ Takes a tuple(x,y) like as argument"""
            
        if not self.mapDim[0]* self.mapDim[1]==0:
            
            x = (iP[0] *-1.0)/ self.mapFactor[0]+self.mapCenter.x
            z = (iP[1] *-1.0)/ self.mapFactor[1]+self.mapCenter.z
            y = self.mapCenter.y
        
            return ogre.Vector3(x,y,z)
        return None
    
    def compute2DPath(self,iStart, iGoal,iMap):
        """ Calculates the A* path between the two (x,y) map positions as argument,
        using iMap as weight map"""
        (w,h)=self.getMapDim(iMap)
        start=self.getMapCoord(iStart)
        end=self.getMapCoord(iGoal)
        
        mh=SQ_MapHandler(iMap,w,h,self.MAP_FORBIDDEN)
        astar = AStar(mh)
        
        p = astar.findPath(start,end)
        
        lwp=None
        
        oDx=0
        oDy=0
        dx=0
        dy=0
        oX=-2000
        oY=-2000
        lastPoint=ogre.Vector3.ZERO
                
        
        if p:
            lwp=[]
            print p
            for pos in p:
                currentPoint=self.getWorldCoord(pos)
                oDx = dx
                oDy = dy
                (x,y)=pos
                dx = x - oX
                dy = y - oY
                oX = x
                oY = y
                if (lastPoint != ogre.Vector3.ZERO):
                    if ((dx == oDx)and(dy == oDy)):
                        del lwp[-1]
                lastPoint = currentPoint
                    
                lwp.append(currentPoint)
        return lwp
        
    
    def doMouseUp(self, loc,  iButton,  iShift,  iCtrl,  iAlt,   iQr,  iSel):
    
        if iButton==OIS.MB_Left:
            if iQr ==  self.QUERY_OTHER_OBJECT or iQr == self.QUERY_OTHER:
                if iSel is not None :
                    if self.currentSelection is not None:
                        self.currentSelection.setSelected(False)
                    self.currentSelection = iSel
                    self.currentSelection.setSelected(True)
                else :
                    logging.warning("ISel = null")
                    return True

            if iQr == self.QUERY_GROUND :
                if iAlt :
                    iP=self.getMapCoord(loc)
                    val = self.getMapValue(iP,self.map)
                    logging.debug(" Map value at %s = %d"%(str(iP),val))
                    logging.debug(" World location = %s" %(str(loc)))
                    logging.debug(" CalcW location = %s" %(str(self.getWorldCoord(iP))))
                    return True
                    

                        
        if iButton==OIS.MB_Right:
                    
                    if self.currentSelection is not None :
                        if self.currentSelection.type:
                            if self.currentSelection.type=="BarrierPole":
                                if iSel is BarrierPole and iSel is not self.currentSelection :
                                    if iCtrl:
                                        self.destroyBarrierLink(iSel, self.currentSelection)
                                        return True
                                    if iShift:
                                        if self.createBarrierLink(iSel, self.currentSelection) is not None :
                                            return True
                                    
                        if self.currentSelection.doMouseUp is not None :
                        
                            logging.debug(" Selected Object %s is going to handle mouse up"%(str(self.currentSelection)))
                            return self.currentSelection.doMouseUp(loc, iButton, iShift, iCtrl, iAlt, iQr, iSel)
                        

        return True
        
    def doMouseDown(self, loc,  iButton,  iShift,  iCtrl,  iAlt,   iQr,  iSel):
        return True


    def checkVisibility(self,A,B):
        for icb in Icebergs.values():
            if icb.isBlocking(A,B) : return False
        return True
    
class Sprite:
    
    
    def getPosition(self):
        if self.sceneNode is not None:
            return self.sceneNode.getPosition()
        return ogre.Vector3.UNIT_X
    
    def setPosition(self,iP):

        if self.sceneNode:
            self.sceneNode.setPosition(iP)

    
    def getOrientation(self):
        return self.sceneNode.getOrientation()
       

    def setOrientation(self,value):
        self.sceneNode.setOrientation(value)
        
    def getName(self):
        return self.name
    

        
    def __init__(self,iName,iSceneNode,iSceneManager,iMeshName,iMaterial):
        self.name=iName
        self.sceneMgr=iSceneManager
        if not iSceneNode:
            self.sceneNode=iSceneManager.getRootSceneNode().createChildSceneNode(iName)
        else :
            self.sceneNode=iSceneNode
        print "Sprite : sceneNode = "+str(self.sceneNode)

        self.entity=None
        
        if iMeshName:
            print iMeshName
            self.entity=iSceneManager.createEntity(iName, iMeshName)
            self.sceneNode.attachObject(self.entity)
            if iMaterial :
                self.entity.setMaterialName (iMaterial)
            else:
                #self.entity.setMaterialName ("whiteBaseLight")
                pass
                
        
        self.setScale(1)
        
        self.sceneNode.setInheritScale(False)
        self.sceneNode.setInheritOrientation(False)
        
        self.setScaleInfo(False,1.0,1.0,1.0)
        
        
    def setScaleInfo(self,iPulse,iMin,iMax,iFreq):
        """Sets pulsing behaviour
		iPulse : boolean : True if this Sprite will pulse with time
		iMin : minimum scale for the sprite
		iMax : maximum scale for the sprite
		iFreq : frequency of pulsation
		"""

        self.pulseBehavior=iPulse
        self.nodeMaxScale = iMax
        self.nodeScale=self.nodeMinScale = iMin
        
        self.pulseFrequency=iFreq
        self.nodeScaleStep = (self.nodeMaxScale-self.nodeMinScale) * self.pulseFrequency
        
    def setScale(self, s):
        self.sceneNode.setScale(s,s,s)
        
    def timerUpdate(self,dt):
        
        if self.pulseBehavior:
            if self.sceneNode is not None:
                self.nodeScale +=  self.nodeScaleStep* dt
                if (self.nodeScale >= self.nodeMaxScale) or (self.nodeScale <= self.nodeMinScale):
                    self.nodeScaleStep = -self.nodeScaleStep
           
                self.sceneNode.setScale(ogre.Vector3.UNIT_SCALE * self.nodeScale)
    
    def __del__(self):
            self.sceneNode.detachAllObjects()
            self.sceneMgr.destroySceneNode(self.sceneNode.getName())
            self.sceneNode = None
            if self.entity :
                self.sceneMgr.destroyEntity(self.entity)
                self.entity = None
        
class LandVehicule(OpenSteer.SimpleVehicule):
    """ This class is a wrapper for SimpleVehicule2D to interface with Ogre3D"""
    
    def __init__(self):
        
        print "Starting LandVehiculeInit"
        OpenSteer.SimpleVehicule.__init__(self,True) 
        self.position=OpenSteer.Vector2D((0.,0.))
        self.mass=1.0
        print "End LandVehiculeInit"
        
        
    def setMass(self,val):
        self.mass=val    
        
        
    def getPosition(self):
        (x,y)=self.position #.asTuple()
        return ogre.Vector3(x,0.0,y)
    
    def setPosition(self,iP):
        OpenSteer.LocalSpace.setPosition(self,(iP.x,iP.z))
        return self.getPosition()
        
    def getOrientation(self):
       
        f=ogre.Vector3(self.forward[0],0.0,self.forward[1])
        s=ogre.Vector3(self.side[0],0.0,self.side[1])
        u=ogre.Vector3(0.0,1.0,0.0)
        
        return ogre.Quaternion(f,u,s)

    def setOrientation(self,value):
        self.setForwardFrom3D(value.xAxis())
        return self.getOrientation()
        
    def move(self, dt, target):

        
        if (target == ogre.Vector3.ZERO) :
            self.applySteeringForce(self.steerForWander(dt), dt)
        else:
            
            self.applySteeringForce(self.steerForSeek((target.x,target.z)), dt)
        


    def slowDown(self, dt):
        if (self.speed == 0.): return
        if (self.speed < 0.1):
            self.setSpeed(0.0)
        else:
            self.setSpeed(self.speed * (1 - self.maxForce * self.mass * dt / 100.0))

        
  
class BarrierPole(Sprite,ITimerUpdatable,ISelectable,IDestroyable):
    
     
    
    def __init__(self, iWorld, iPos, iName,  iObstacleMap):
        
        IDestroyable.__init__(self,100)
        Sprite.__init__(self,iName,None,iWorld.MainWindow.SceneMgr,"sphere.mesh",None)

        self.world=iWorld
        
        self.setPosition(iPos)
        self.type="BarrierPole"
        self.obstacleMap=iObstacleMap
        
        self.peers=[]
        
        self.setScale(0.1)
        
        self.entity.setVisible (False)
        self.entity.setQueryFlags(iWorld.SELECTABLE_MASK|iWorld.HUMAN_MASK)
        
        self.billboard = GlowingBillboard(iWorld,self.sceneNode.createChildSceneNode(),\
                    iName,"Alpha/BlueLight")
        
    def timerUpdate(self, dt):
    
        if self.billboard is not None:
            return self.billboard.timerUpdate(dt)
        return True

    def __del__(self):
        print "[%s] HELP, I am being deleted !"%(self.name)
        del self.billboard
        self.world.MainWindow.SceneMgr.destroyEntity(self.entity)
        self.world.MainWindow.SceneMgr.destroySceneNode(self.sceneNode.getName())
        
    def doMouseUp(self, iPos, iButton, isShift, isCtrl, isAlt, iQr, iMO):
        if isAlt and iButton==OIS.MB_Right:
            self.world.destroyBarrierPole(self)
            return True
        
        return False
    
    
class BarrierLink(Sprite):
    
    def getPeers(self):
        return self.peers
    
    
    __class__="BarrierLink"
    
    def __init__(self,iName, ibp1,ibp2, iWorld):
        
        
        self.name=iName
        Sprite.__init__(self,iName,None,iWorld.MainWindow.SceneMgr,None,None)
        
        self.peers=(ibp1,ibp2)
        
        v=ibp1.getPosition()-ibp2.getPosition()
        
        self.sceneNodeChild = self.sceneNode.createChildSceneNode(v * 0.5)
            
        self.entity=self.sceneMgr.createEntity(iName , "barrierlink")
        self.entity.setMaterialName ( "Alpha/Barrier")
        
        q = ogre.Vector3.UNIT_X.getRotationTo(v.normalisedCopy())

        self.sceneNodeChild.setOrientation ( q)
        self.sceneNodeChild.setScale(v.length() / 32, 1, 1)

        self.sceneNodeChild.attachObject(self.entity)
        
    def isLinking(self,iBP):
        return iBP in self.peers
    
    def __del__(self):
        self.sceneNodeChild.detachAllObjects()
        self.sceneMgr.destroySceneNode(self.sceneNodeChild.getName())
        
        Sprite.__del__()    
        
        self.peers=None

       
class GlowingBillboard(ITimerUpdatable):
    
    
    def __init__(self,iWorld,iSceneNode,iName,iMat):
        
        self.name=iName
        self.world=iWorld
        
        self.parentSceneNode=iSceneNode
        self.nodeMaxScale = 0.8
        self.nodeScale=self.nodeMinScale = 0.1
        
        self.frequency=2.0
        self.nodeScaleStep = (self.nodeMaxScale-self.nodeMinScale) * self.frequency
        

        self.billboardSet = ogre.BillboardSet(iName)
        self.billboardSet.setMaterialName (iMat)

        
        self.billBoard = self.billboardSet.createBillboard\
            (ogre.Vector3.ZERO)
        
        self.attach(iSceneNode)
        
    def detach(self):
        if self.parentSceneNode is not None:
                self.parentSceneNode.detachObject(self.name)
        
        #self.world.MainWindow.SceneMgr.destroySceneNode(self.parentSceneNode.getName())
        
        
    
    def attach(self,iSceneNode):
        self.parentSceneNode=iSceneNode
        self.parentSceneNode.setInheritScale (False)
        
        self.parentSceneNode.setInheritOrientation (False)
        self.parentSceneNode.setScale(ogre.Vector3.UNIT_SCALE * self.nodeMinScale)
        self.parentSceneNode.attachObject(self.billboardSet)
        
                
    def timerUpdate(self, dt):
        if self.parentSceneNode is not None:
            self.nodeScale +=  self.nodeScaleStep* 0.001
            if (self.nodeScale >= self.nodeMaxScale) or (self.nodeScale <= self.nodeMinScale):
                self.nodeScaleStep = -self.nodeScaleStep
       
            self.parentSceneNode.setScale(ogre.Vector3.UNIT_SCALE * self.nodeScale)
        
        return True
    
    def __del__(self):
        print "BB destroying itself"
        self.detach()
        self.billboardSet.dispose()
        del self.billboardSet
        
   

class LightTower:
    
    def __init__(self,iParent, iName, iRange,  iHeight):
        
        self.parent = iParent
        self.yaw = 0.0
        self.cycle = 0.0
        self.direction = 3.141592
        self.amplitude = 1.0
        self.name = iName
        self.range = iRange
        self.light=self.parent.world.MainWindow.SceneMgr.createLight(iName\
            + "_Light1")
        self.light.Type = ogre.Light.LightTypes.LT_SPOTLIGHT
        self.light.DiffuseColour = ogre.ColourValue.Green
        
        self.FOV=ogre.Degree(45)
        #mParent.ContainingWorld.MainWindow.log("mLight :" + mLight.AttenuationRange + " / " + mLight.AttenuationConstant + " / " + mLight.AttenuationLinear + " / " + mLight.AttenuationQuadric);
        
        self.light.setAttenuation(self.range, 0.0001,0.001, 0.0000004)
        #mParent.ContainingWorld.MainWindow.log("mLight :" + mLight.AttenuationRange + " / " + mLight.AttenuationConstant + " / " + mLight.AttenuationLinear + " / " + mLight.AttenuationQuadric);
        self.light.setSpotlightRange(ogre.Degree(30), self.FOV,1.0)
        
        q=ogre.Quaternion()
        q.FromAngleAxis(ogre.Radian(ogre.Degree(0)), ogre.Vector3.NEGATIVE_UNIT_Z)
        self.light.Direction = q*ogre.Vector3.UNIT_X
        

        self.sceneNode = self.parent.sceneNode.createChildSceneNode()
        self.sceneNode.setInheritScale (False)
        self.sceneNode.translate(1.0, iHeight, 0)
        self.sceneNode.attachObject(self.light)
        
    def getName(self):
        return self.name
    
    def setDirAmpl(self, iDest):
        
            minLength = 20.0
            
            iDest.y=self.parent.getPosition().y
            src = self.parent.getOrientation() * ogre.Vector3.UNIT_X
            iDiff= iDest - self.parent.getPosition()
            length = iDiff.length()
            if length < 10.0 : length=10.0
            
            dp=src.dotProduct(iDiff)
            right = src.crossProduct(ogre.Vector3.NEGATIVE_UNIT_Y)

            th = ogre.Math.ACos(dp / length).valueRadians()

            if right.dotProduct(iDiff)<0 :
                self.direction =   -th
            else :
                self.direction =   th

            self.amplitude = 3.14159/ (length*length) * minLength*minLength
            
    def doTimer(self,dt):
    
        self.cycle += dt
        self.cycle %= (3.141592 * 2)
        
        self.yaw = self.direction + ogre.Math.Cos(self.cycle) * self.amplitude

        
        q = ogre.Quaternion(self.yaw, ogre.Vector3.UNIT_Y)
        self.sceneNode.setOrientation(q) 
        
    def __del__(self):
        self.parent.ContainingWorld.MainWindow.SceneMgr.destroyLight(self.light)
        self.light.dispose()
        self.parent.ContainingWorld.MainWindow.SceneMgr.destroySceneNode(self.sceneNode.getName())
        self.sceneNode.dispose()      

class MobileObject(Sprite,IDestroyable,ITimerUpdatable,ISelectable):
    
    CONTACT_DISTANCE=20
    BEHAVIOUR_FOLLOW_PATH=1
    BEHAVIOUR_IDLE=2
    
    
    def getSelected(self):
        return self.selected
    
    def setSelected(self,value):
        self.selected=value
        
        ## Not very nice...
        ## asks the world parent object to move the selection marker
        if value:
            self.world.BBS.detach()
            self.world.BBS.attach(self.nodeSelect)
            
            
        else:
            pass
        print("***old : " + self.world.strV3(self.getPosition()))
           #self.nodeSelect.detachObject(self.world.BBS)
        

    
    def flatDistanceTo(self,iMO):
        pos = ogre.Vector2(self.node.getPosition().x-iMO.getPosition().x, self.node.getPosition().z-iMO.getPosition().z)
        return pos.Length
    
    def getSize(self):
        return self.size
    def setSize(self,value):
        self.size=value

    
    def __init__(self,iWorld, iName, iPos, iOrient,iMeshName,iMaterial):
        print ("Entering MobileObject init,with following values ",iWorld,iName,iPos,iOrient)
        Sprite.__init__(self,iName,None,iWorld.MainWindow.SceneMgr,iMeshName,iMaterial)
        self.world=iWorld
        print "Sprite init OK for "+ self.name
        self.size=20
        
        self.setPosition(iPos)
        self.setOrientation(iOrient)
        
        self.dead=False
            
        self.selected=False
        print ("End of MobileObject init")
        
        self.nodeSelect=self.sceneNode.createChildSceneNode()
        self.nodeSelect.translate(0,15,0)
    

    def __del__(self):
        self.dead=True
        Sprite.__del__()
        
    

class T_WayPoint(Sprite):
    
        def __init__(self, iWorld, iPos,iName):
            logging.info("new WP")
            
            Sprite.__init__(self,iName,None,iWorld.MainWindow.SceneMgr,"sphere.mesh",None)
            
            self.setScale(0.1)
            
            self.sceneNode.setPosition(iPos)
            
        def __del__(self):
            Sprite.__del__()
            
            
        

class Iceberg(Sprite):
    def __init__(self,iWorld,iName,iPoints):
    
        mo=ogre.ManualObject(iName)
        mo.begin("whiteBaseLight", ogre.RenderOperation.OT_TRIANGLE_LIST)
        for (x0,z0) in iPoints:
            mo.position(x0,0.,z0)
            mo.position(x0,100,z0)
            
        for i in range(len(iPoints)-1):
            j=i*2
            mo.triangle(j,j+1,j+3)
            mo.triangle(j,j+3,j+2)
            
        j=(len(iPoints)-1)*2
        mo.triangle(j,0,j+1)
        mo.triangle(j,1,0)
        mo.end()
    
        mo.convertToMesh(iName+"Mesh")
        
        Sprite.__init__(self,iName,None,iWorld.MainWindow.SceneMgr,iName+"Mesh",None)
        self.points=iPoints
        height=100.
        
        
        self.entity.setCastShadows (True)
        
        self.entity.setQueryFlags(World.TERRAIN_MASK)
        
        
        
    def isBlocking(self,obs,target):
        """ Checks if this iceberg is blocking the view from observer
        to target.
        Takes two ogre.Vector3 as arguments
        """
        A=(obs.x,obsz)
        B=(target.x,target.z)
        SegA=self.points[0]
        
        for i in range(1,len(self.points)):
            SegB=self.points[i]
            if util.intersect(A,B,SegA,SegB):
                return True
            SegA=SegB
        return False
                

class MobileActor(MobileObject):
    
    
    def setPosition(self, iPos):
        
        print "MA -> SetPos "
        iPos=self.lv.setPosition(iPos)
        MobileObject.setPosition(self,iPos)
        print "OK"
    
    def setOrientation(self,iO):
        
        iO=self.lv.setOrientation(iO)
        MobileObject.setOrientation(self,iO)
    
    def __init__(self,iWorld, iName, iPos, iOrient, iMeshName,iMaterial):
        
        self.type="MobileActor"
        self.entity=None
        self.dead=False
        self.lv=LandVehicule()
       
        
        MobileObject.__init__(self,iWorld, iName, iPos, iOrient,iMeshName,iMaterial)

        self.actionQueue=[]

        self.waypoints=[]
        self.wpcounter=0
        
        self.setScale(5)

            
        self.behaviour=MobileActor.BEHAVIOUR_IDLE
        
        self.lv.setMaxSpeed(50.0)
        self.lv.setMaxForce(50.0)
        
        self.lv.setMass(1.0)
         
        self.entity.setQueryFlags(iWorld.SELECTABLE_MASK|iWorld.HUMAN_MASK)
        
        self.lightTower = LightTower(self, iName + "_LT",300.0, 15.0)
        
        self.CONTACT_DISTANCE=20
            
    def __del__(self):
        self.dead=True
        self.clearPath()
        del self.lightTower
        MobileObject.__del__()
        
           
    def doMouseDown(self,loc, iButton, iShift,  iCtrl,  iAlt,  iQr,  iMO):
       
        
        return True
    
    
    def parseActionQueue(self):
        if len(self.actionQueue)<1 :return
        action=self.actionQueue.pop(0)
        if action[0]=="ADD_WAYPOINT" :
            loc,shiftup,alt=action[1]
            self.addWayPoint(loc, shiftup, alt)
            
        elif action[0]=="CHANGE_RADAR" : 
            loc=action[1]
            
            self.lightTower.setDirAmpl(loc)
            
    def doMouseUp(self,loc, iButton,  iShift,  iCtrl,  iAlt,  iQr,  iMO):
        
        if iButton==OIS.MB_Right:
            print("Treated MouseDown message : MB_RIGHT")
            if iCtrl:
                self.actionQueue.append(("CHANGE_RADAR",loc))
                
                return True

            if iQr == self.world.QUERY_GROUND:
                self.actionQueue.append(("ADD_WAYPOINT",(loc, not iShift, iAlt)))
                #self.addWayPoint(loc, not iShift, iAlt)
                print("Treated MouseDown message : MB_RIGHT")
                return True
        
        return True
    
    def timerUpdate(self, iTimeInterval):
        if self.dead:
            print("DeadManWalking!")
            return True
        returnValue = Sprite.timerUpdate(self,iTimeInterval)
        self.move(iTimeInterval)
        
        self.parseActionQueue()
        
        if self.lightTower:
            self.lightTower.doTimer(iTimeInterval)

        return returnValue
    
    
       
        
    def move(self, timeInterval):
        """ Move without constriaint, typical for flying objects..."""

        if self.behaviour==MobileObject.BEHAVIOUR_FOLLOW_PATH:
            
            if len(self.waypoints)>0:
                dest=self.waypoints[0].getPosition()
                
                self.lv.move(timeInterval,dest)
                
                dist=dest-self.lv.getPosition()
                if dist.length() < self.CONTACT_DISTANCE:
                    wp=self.waypoints.pop(0)
                    del wp
        
        if len(self.waypoints)==0:
            self.behaviour=MobileObject.BEHAVIOUR_IDLE
            
        if self.behaviour==MobileObject.BEHAVIOUR_IDLE:
            self.lv.slowDown(timeInterval)    
        
        q=self.lv.getOrientation()
        #q=ogre.Quaternion(tuple(self.lv.forward),tuple(self.lv.up),tuple(self.lv.side))
        MobileObject.setPosition(self,self.lv.getPosition())
        MobileObject.setOrientation(self,q)
        
    
        
            
    def clearPath(self):
        for i in range(len(self.waypoints)-1, 0, -1):
            tmp=self.waypoints.pop()
            del tmp
        self.behaviour = MobileActor.BEHAVIOUR_IDLE
        
    def addWayPoint(self, iLoc,  clear, useAStar):
        logging.info("Entering addWayPOint for actor %s"%(self.name))
        if self.behaviour==MobileActor.BEHAVIOUR_IDLE or self.behaviour==MobileActor.BEHAVIOUR_FOLLOW_PATH:
            logging.info("Entering addWayPOint for actor %s"%(self.name))
            
            if clear :
                self.clearPath()
            
            self.behaviour=MobileObject.BEHAVIOUR_FOLLOW_PATH
            logging.info("...in addWP")
            # Check if is using a path finding algorythm
            if useAStar:
                logging.info("Using an A* algo")
                lwp=self.world.compute2DPath(self.node.getPosition(),iLoc,self.world.friendlyMap)
                # if no path can be found
                if not lwp:
                    self.behaviour = MobileActor.BEHAVIOUR_IDLE
            
                else:
                    self.behaviour = MobileActor.BEHAVIOUR_FOLLOW_PATH
                    for v in lwp:
                        wp=T_WayPoint(self.world,v,self.getName()+"_wp#"+str(self.wpcounter))
                        self.wpcounter=self.wpcounter+1
                        self.waypoints.append(wp)

            else: # if not using path finding, just add the point.
                logging.info("new waypoint at %s"%(str(iLoc)))
                wp=T_WayPoint(self.world,iLoc,self.name+"_wp#"+str(self.wpcounter))
                self.wpcounter=self.wpcounter+1
                self.waypoints.append(wp)
                logging.info("size of waypoints : %d"%(len(self.waypoints)))
            

    